/* Copyright (C) 2007-2008  klevgert  http://code.google.com/p/db4o-netbeans/

This file is part of the db4o-netbeans module suite.

db4o-netbeans is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL 
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.

db4o-netbeans is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */

package com.db4o.nb.editor.nodes;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.ext.ExtObjectContainer;
import com.db4o.ext.ObjectInfo;
import com.db4o.ext.StoredClass;
import com.db4o.nb.util.PreferencesUtil;
import com.db4o.nb.util.Updateable;
import com.db4o.query.Query;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.Action;
import org.openide.ErrorManager;
import org.openide.actions.PropertiesAction;
import org.openide.loaders.DataObject;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Index;
import org.openide.nodes.Node.Property;
import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.actions.SystemAction;
import org.openide.util.lookup.Lookups;

/**
 * Manages the db4o object set obtained in response to a query.
 *   
 * @author klevgert
 */
public class ObjectSetNode extends AbstractNode implements Updateable {
  
  private static final String ICON_PATH = "com/db4o/nb/editor/resources/beantree.gif";

  private ObjectSet objectSet;
  private ObjectContainer objectContainer;
  private int thresholdFactor = 1;
  
  /**
   * Creates a new instance of ObjectSetNode
   */
  public ObjectSetNode(ObjectSet os, ObjectContainer oc, DataObject dataObj) {
    super( new ObjectSetNodeChildren(os, oc), Lookups.fixed( new Object[] { os, oc, dataObj }) );
    
    this.objectSet = os;
    this.objectContainer = oc;

    this.setDisplayName("Objects #" + os.size());
    this.setIconBaseWithExtension(ICON_PATH);
  }

  public ObjectContainer getObjectContainer() {
    return objectContainer;
  }

  public ObjectSet getObjectSet() {
    return objectSet;
  }
  
  public int getThresholdFactor() {
    return thresholdFactor;
  }

  public void setThresholdFactor(int thresholdFactor) {
    this.thresholdFactor = thresholdFactor;
  }

  public void incrementThresholdFactor() {
    this.setThresholdFactor(this.getThresholdFactor() + 1);
  }

  public void reloadChildren() {
    this.setChildren(new ObjectSetNodeChildren(this.objectSet,this.objectContainer));
  }
  
  public void update() {
    this.incrementThresholdFactor();
    this.reloadChildren();
  }  
  
  public Action[] getActions(boolean popup) {
    return new Action[] {
      SystemAction.get(PropertiesAction.class)      
    };
  }
  
  protected Sheet createSheet() {
    Sheet sheet = Sheet.createDefault();
    Sheet.Set set = sheet.createPropertiesSet();
    try {
      
      set.put (createNameProperty());
      set.put (createObjectCountProperty());
        
    } catch (Exception ex) {
        ErrorManager.getDefault().notify (ex);
    }
    sheet.put(set);
    return sheet;
  }  

  private Property createObjectCountProperty() {
    
    String displayName = NbBundle.getMessage(this.getClass(), "ObjectCount");
    Property countProp = new PropertySupport.ReadOnly("count", String.class, 
            displayName, null) {
      public Object getValue() {
        return ""+ObjectSetNode.this.getObjectSet().size();
      }
    };
    countProp.setName("count");
    return countProp;
  }

  private Property createNameProperty() {
    String displayName = NbBundle.getMessage(this.getClass(), "Name");
    Property nameProp = new PropertySupport.ReadOnly("name", String.class, 
            displayName, null) {
      public Object getValue() {
        return ObjectSetNode.this.getDisplayName();
      }
    };
    nameProp.setName("name");
    return nameProp;
  }

  // <editor-fold defaultstate="collapsed" desc=" Children ">                          

   /**
   *
   * @author klevgert
   */
  public static class ObjectSetNodeChildren extends Index.ArrayChildren {

    private Query query ;
    private ObjectSet objectSet;
    private ObjectContainer objectContainer;

    /**
     * Creates a new instance of ObjectSetChildren
     */
    public ObjectSetNodeChildren(ObjectSet os, ObjectContainer oc) {

      this.objectSet = os;
      this.objectContainer = oc;

    }

    protected Collection initCollection() {

      // Get the value how many instances should be displayed
      int thrVal = PreferencesUtil.getThresholdValue();
      int thresholdValue = thrVal*((ObjectSetNode)this.getNode()).getThresholdFactor(); 

      ExtObjectContainer eoc = this.objectContainer.ext();
      long[] oids = objectSet.ext().getIDs();

      int cnt = (oids.length < thresholdValue)? oids.length : thresholdValue;

      ArrayList childrenNodes = new ArrayList( cnt+1 );
      for (int j = 0; j < cnt; j++) {

        ObjectInfo oi = eoc.getObjectInfo(eoc.getByID(oids[j]));
        StoredClass sc = eoc.storedClass(oi.getObject());

        AbstractNode result = new ObjectNode(oids[j], this.objectContainer);
        childrenNodes.add(result);

        eoc.activate(oi.getObject(),2);
      }

      if( oids.length > thresholdValue ) {
        AbstractNode result = new MoreObjectsNode(oids.length-thresholdValue);
        childrenNodes.add(result);
      }
      return childrenNodes;

    }
  }
  // </editor-fold>                          

}
